package cc.siyecao.fastdfs.command.tracker;

import cc.siyecao.fastdfs.model.RecvPackageInfo;
import cc.siyecao.fastdfs.model.StorageInfo;
import cc.siyecao.fastdfs.protocol.ProtocolConstants;
import cc.siyecao.fastdfs.util.BytesUtil;
import cc.siyecao.fastdfs.util.ProtocolUtil;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

/**
 * 获取源服务器
 *
 * @author lyt
 */
public class GetFetchStoragesCommand extends FdfsTrackerCommand<List<StorageInfo>> {

    public GetFetchStoragesCommand(String groupName, String fileName) {
        this.groupName = groupName;
        this.fileName = fileName;
    }

    @Override
    protected void send(OutputStream out, Charset charset) throws Exception {
        byte[] header;
        byte[] bFileName;
        byte[] bGroupName;
        byte[] bs;
        int len;
        bs = groupName.getBytes( charset );
        bGroupName = new byte[ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN];
        bFileName = fileName.getBytes( charset );

        if (bs.length <= ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN) {
            len = bs.length;
        } else {
            len = ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN;
        }
        Arrays.fill( bGroupName, (byte) 0 );
        System.arraycopy( bs, 0, bGroupName, 0, len );

        header = ProtocolUtil.packHeader( TRACKER_PROTO_CMD_SERVICE_QUERY_FETCH_ALL, ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN + bFileName.length, (byte) 0 );
        byte[] wholePkg = new byte[header.length + bGroupName.length + bFileName.length];
        System.arraycopy( header, 0, wholePkg, 0, header.length );
        System.arraycopy( bGroupName, 0, wholePkg, header.length, bGroupName.length );
        System.arraycopy( bFileName, 0, wholePkg, header.length + bGroupName.length, bFileName.length );
        out.write( wholePkg );
    }

    @Override
    protected List<StorageInfo> receive(InputStream in, Charset charset) throws Exception {
        RecvPackageInfo pkgInfo = ProtocolUtil.recvPackage( in, TRACKER_PROTO_CMD_RESP, -1 );
        this.errno = pkgInfo.errno;
        if (pkgInfo.errno != 0) {
            return null;
        }

        if (pkgInfo.body.length < ProtocolConstants.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN) {
            throw new IOException( "Invalid body length: " + pkgInfo.body.length );
        }

        if ((pkgInfo.body.length - ProtocolConstants.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN) % (ProtocolConstants.FDFS_IPADDR_SIZE - 1) != 0) {
            throw new IOException( "Invalid body length: " + pkgInfo.body.length );
        }

        int serverCount = 1 + (pkgInfo.body.length - ProtocolConstants.TRACKER_QUERY_STORAGE_FETCH_BODY_LEN) / (ProtocolConstants.FDFS_IPADDR_SIZE - 1);

        String ipAddr = new String( pkgInfo.body, ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN, ProtocolConstants.FDFS_IPADDR_SIZE - 1 ).trim();
        int offset = ProtocolConstants.FDFS_GROUP_NAME_MAX_LEN + ProtocolConstants.FDFS_IPADDR_SIZE - 1;

        int port = (int) BytesUtil.buff2long( pkgInfo.body, offset );
        offset += ProtocolConstants.FDFS_PROTO_PKG_LEN_SIZE;

        StorageInfo[] servers = new StorageInfo[serverCount];
        servers[0] = new StorageInfo( ipAddr, port, (byte) 0 );
        for (int i = 1; i < serverCount; i++) {
            servers[i] = new StorageInfo( new String( pkgInfo.body, offset, ProtocolConstants.FDFS_IPADDR_SIZE - 1 ).trim(), port, (byte) 0 );
            offset += ProtocolConstants.FDFS_IPADDR_SIZE - 1;
        }
        return Arrays.asList( servers );
    }
}
